#ifndef _SYNFX_H
#define _SYNFX_H

#include "syncommon.h"

namespace Synth {

class Delay {
	float delayBuffer[32768];
	int delayPos;
	int delaySize;
public:
	Delay() {delaySize = 4000;}
	void setSize(int lengthInSamples);
	void Render(Block buffer, float amount, float feedback);
};

enum {
	FILTER_OFF,
	FILTER_HIGHPASS,
	FILTER_NOTCH,
	FILTER_BANDPASS,
	FILTER_LOWPASS,
};

// Simple State Variable Filter
class SVFFilter {
	float lo, hi, bp, bs;
public:
	SVFFilter() {
		//low=band=high=0.0f;
		Reset();
		//memset(&lo,0,sizeof(float)*8);
	}
	void Render(Block where, float cutoff, float resonance, int type);
	void Reset();
};

class FormantFilter {
	double memory[10];
public:
	FormantFilter() {
		memset(memory, 0, sizeof(memory));
	}
	void Render(Block where, int vowel);
};

class MoogFilter {
private:
	float y1, y2, y3, y4,
          oldx, oldy1, oldy2, oldy3;
public:
	MoogFilter() : y1(0), y2(0), y3(0), y4(0), oldx(0), oldy1(0), oldy2(0), oldy3(0) {
	}
	void Render(Block buf, float cutoff, float res);
};

class DownsamplingFilter {
	float state;
public:
	DownsamplingFilter() {
		state = 0;
	}
	void Process(Block inblock, Block outblock, int n) {
		if (OVERSAMPLE_FACTOR == 1) {
			memcpy(outblock, inblock, BLOCKSIZE * sizeof(float));
		}
		else {
			int outp = (BLOCKSIZE / OVERSAMPLE_FACTOR) * n;
			for (int i = 0; i < BLOCKSIZE / OVERSAMPLE_FACTOR; i++) {
				for (int j = 0; j < OVERSAMPLE_FACTOR; j++) {
					state += *inblock++;
					state *= 0.5f;
				}
				outblock[outp + i] = state;
			}
		}
	}
};

// Maybe put some of these in the reverb?
class AllpassDelay {
public:
	AllpassDelay() : _zm1(0.f) {}
	static float ComputeDelay(float delay) { //sample delay time
    	return (1.f - delay) / (1.f + delay);
    }
    float Update(float inSamp, float _a1) {
    	float y = inSamp * -_a1 + _zm1;
    	_zm1 = y * _a1 + inSamp;
        return y;
    }
private:
	float _zm1;
};


class Phaser {
public:
	  //initialise to some usefull defaults...
	Phaser() : _zm1( 0.f ) {
    }
    void Render(Block buf, float frequency, float feedback, float amount);
private:
    AllpassDelay _alps[6];
    float _zm1;
};


enum LFOMode {
	LFOPositive,
	LFONegative,
	LFOBipolar
};

class LFO {
	float t;
	float heldSample;
	float lastHeldSample;
public:
	LFO() {t = heldSample = lastHeldSample = 0;}
	void SetT(float _t) {t = _t;}
	float GetValue(float phase, int waveform, int mode, float speed);
};

struct EnvParams {
	float attack;
	float decay;
	float sustain;
	float release;
	float amount;
};

enum EnvPhase {
	EP_DEAD,
	EP_ATTACK,
	EP_DECAY,
	EP_SUSTAIN,
	EP_RELEASE,
};

class Envelope {
	float value;
	float scale;

	bool rising;
	bool gate;
public:
	Envelope() {
		phase = EP_DEAD;
		rising = false;
		gate = false;
	}
	void Render(Block buf);
	bool IsDead() const {
		return phase == EP_DEAD;
	}
	bool Gated() const {
		return gate;
	}
	float GetValue() const { return (value - 1) * scale; }
	void SetScale(float s) {
		scale = s;
	}
	void KeyDown();
	void KeyUp();

	EnvParams *params;
	EnvPhase phase;
};

class Reverb {
public:
	enum {
		NUMDELAYLINES=6
	};

	float *buffer;
	float *buffers[NUMDELAYLINES];
	int length[NUMDELAYLINES];
	float low[NUMDELAYLINES];
	int pos[NUMDELAYLINES];

	void Init(const short len[NUMDELAYLINES]);
	void Shutdown();
	void Render(Block buf, float halfLife, float pole);
	void Silence();
};

class Distorter {
	int counter;
	float hold;
public:
	Distorter() {hold = 0;}
	void Distort(Block buf, float amount, float foldback, int type);
	
};

}  // namespace

#endif